use sea_orm::{
    ActiveModelTrait, ColumnTrait, DatabaseConnection, DbErr, EntityTrait, 
    IntoActiveModel, QueryFilter, QueryOrder, Set
};
use chrono::Utc;
use crate::models::rbac::department::{SafeDepartment, DepartmentTree};
use crate::entities::rbac::departments::{Model as Department, Entity as DepartmentEntity,  Column as DepartmentColumn};
use crate::{service, empty_ok, json_ok, utils, AppResult, EmptyResult, JsonResult};


pub struct DepartmentService;

impl DepartmentService {
    pub async fn create(
        model: & Department,
    ) -> AppResult<Department> {
        let db  = service::pool();
        let entity = crate::entities::rbac::departments::ActiveModel {
            name: Set(model.name.to_owned()),
            parent_id: Set(model.parent_id.to_owned()),
            order_num: Set(model.order_num.to_owned()),
            create_by: Set(model.create_by.to_owned()),
            update_by: Set(model.update_by.to_owned()),
            tenant_id: Set(model.tenant_id.to_owned()),
            ..Default::default()
        };

        let res = entity.insert(db).await?;

        Ok(res)
    }
    
    /**
     * update and logic deleted 
     * 
     * */ 
    pub async fn update(
        model: & Department,
    ) -> AppResult<Department> {
        let db  = service::pool();
        let mut department = DepartmentEntity::find_by_id(model.id.to_owned())
            .one(db)
            .await?
            .ok_or(DbErr::RecordNotFound("Department not found".to_string()))?
            .into_active_model();

            department.name = Set(model.name.to_owned());
            department.order_num = Set(model.order_num.to_owned());
            department.remark = Set(model.remark.to_owned());
            department.status = Set(model.status.to_owned());
            department.tenant_id = Set(model.tenant_id.to_owned());
            department.deleted = Set(model.deleted.to_owned());
            department.update_by = Set(model.update_by.to_owned());
            department.update_time = Set(Some(Utc::now().naive_utc()));
            department.update_time = Set(Some(Utc::now().naive_utc()));

        let res = department.update(db).await?;
        Ok(res)
    }

    pub async fn delete(
        db: &DatabaseConnection,
        department_id: &str,
        tenant_id: Option<i64>
    ) -> Result<u64, DbErr> {
        let res = DepartmentEntity::delete_many()
            .filter(DepartmentColumn::Id.eq(department_id))
            .filter(DepartmentColumn::TenantId.eq(tenant_id))
            .exec(db)
            .await?;

        Ok(res.rows_affected)
    }

    pub async fn find_by_id(
        db: &DatabaseConnection,
        id: &str,
        tenant_id: Option<i64>
    ) -> Result<Option<Department>, DbErr> {
        DepartmentEntity::find()
            .filter(DepartmentColumn::Id.eq(id))
            .filter(DepartmentColumn::TenantId.eq(tenant_id))
            .one(db)
            .await
    }

    pub async fn find_all(
        tenant_id: Option<i64>
    ) -> Result<Vec<Department>, DbErr> {
        let db  = service::pool();
        let departments = DepartmentEntity::find()
            .filter(DepartmentColumn::TenantId.eq(tenant_id))
            .order_by_asc(DepartmentColumn::Name)
            .all(db)
            .await?;

        Ok(departments.into_iter().map(|d| Department {
            id: d.id,
            department_id: d.department_id,
            order_num: d.order_num,
            name: d.name,
            status: d.status,
            remark: d.remark,
            deleted: d.deleted,
            parent_id: d.parent_id,
            tenant_id: d.tenant_id,
            create_by: d.create_by,
            create_time: d.create_time,
            update_by: d.update_by,
            update_time: d.update_time,
        }).collect())
    }

    pub async fn find_tree(
        tenant_id: Option<i64>
    ) -> Result<Vec<DepartmentTree>, DbErr> {
        let db  = service::pool();
        let departments = DepartmentEntity::find()
            .filter(DepartmentColumn::TenantId.eq(tenant_id))
            .order_by_asc(DepartmentColumn::Name)
            .all(db)
            .await?;

        let mut tree = Vec::new();
        let mut map = std::collections::HashMap::new();

        // Build department map
        for dept in &departments {
            map.insert(dept.id.clone(), dept);
        }

        // Build tree structure
        for dept in &departments {
            if dept.parent_id.is_none() {
                tree.push(DepartmentTree {
                    id: dept.id.to_owned(),
                    name: dept.name.clone(),
                    department_id: dept.department_id.to_owned(),
                    parent_id: dept.parent_id.to_owned(),
                    tenant_id: dept.tenant_id.unwrap(),
                    create_by: dept.create_by.clone().unwrap(),
                    create_time: dept.create_time.unwrap(),
                    update_by: dept.update_by.clone().unwrap(),
                    update_time: dept.update_time.unwrap(),
                    children: Vec::new(),
                });
            }
        }

        // Add children
        for dept in &departments {
            if let Some(parent_id) = &dept.parent_id {
                if let Some(parent) = tree.iter_mut().find(|p| p.id == *parent_id) {
                    parent.children.push(DepartmentTree {
                        id: dept.id.to_owned(),
                        name: dept.name.to_owned(),
                        department_id: dept.department_id.to_owned(),
                        parent_id: dept.parent_id,
                        tenant_id: dept.tenant_id.unwrap(),
                        create_by: dept.create_by.clone().unwrap(),
                        create_time: dept.create_time.unwrap(),
                        update_by: dept.update_by.clone().unwrap(),
                        update_time: dept.update_time.unwrap(),
                        children: Vec::new(),
                    });
                }
            }
        }

        Ok(tree)
    }
}
